package data;

import java.util.ArrayList;

import util.MyBitSet;

public class DataBloc {

	private MyBitSet data;

	private final int size = 64;

	public MyBitSet getValue() {
		return data;
	}

	public DataBloc(MyBitSet data) {
		if (data.getSize() != size) {
			throw new WrongSizeException();
		}
		this.data = data;
	}

	/**
	 * construit un DataBloc à partir d'un tableau de Byte de taille 8
	 * 
	 * @param b
	 */
	public DataBloc(Byte[] b) {
		this();
		if (b.length != 8) {
			throw new WrongSizeException();
		}
		// pour les 8 bytes de b
		for (int i = 0; i < 8; i++) {
			// pour le 8 bits de b[i]
			for (int j = 0; j < 8; j++)
				//
				if (getBit(b[i], j))
					data.set(j + i * 8, true);
				else
					data.set(j + i * 8, false);
		}
	}

	public DataBloc() {
		this.data = new MyBitSet(size);
	}

	/**
	 * transforme une chaîne de caractères en ArrayList de DataBloc
	 * 
	 * @param text
	 * @return
	 */
	public static ArrayList<DataBloc> toDataBloc(String text) {
		byte[] tabByte = null;
		tabByte = text.getBytes();
		ArrayList<Byte[]> listByte = new ArrayList<Byte[]>();
		int indexListe = -1;
		int indexTab = 0;
		for (int i = 0; i < tabByte.length; i++) {
			if (indexTab % 8 == 0) {
				listByte.add(new Byte[8]);
				indexListe++;
				indexTab = 0;
			}
			listByte.get(indexListe)[indexTab] = tabByte[i];
			indexTab++;
		}
		// on ajoute des bits de bourage
		if (indexTab < 8) {
			for (int i = indexTab; i < 8; i++) {
				listByte.get(indexListe)[i] = (byte) 0;
			}
		}
		// on remplie l'array list result
		ArrayList<DataBloc> result = new ArrayList<DataBloc>();
		for (int i = 0; i < listByte.size(); i++) {
			result.add(new DataBloc(listByte.get(i)));
		}
		return result;

	}

	/**
	 * Transforme une ArrayList\<DataBloc\> en chaîne de caractère.
	 * 
	 * @param plainText
	 * @return
	 */
	public static String toString(ArrayList<DataBloc> text) {
		byte[] byteResult = new byte[text.size() * 8];
		// pour tout les DataBloc
		for (int i = 0; i < text.size(); i++) {
			// pour chaque groupe de 8 bits
			for (int j = 0; j < 8; j++) {
				byteResult[i * 8 + j] = (byte) 0;
				// pour chaque bit du groupe de 8 bit
				for (int k = 0; k < 8; k++) {
					if (text.get(i).getValue().get(j * 8 + k)) {
						byteResult[i * 8 + j] = setBit(byteResult[i * 8 + j],
								k, true);
					}
				}
			}
		}

		String result = new String(byteResult);
		return result;
	}

	/**
	 * met le bit n°i (bit 0 => bit de poids fort bit 7 => bit de poids faible) à
	 * la val val;
	 * 
	 * @param b
	 *            non modifié
	 * @param i
	 *            indice du bit
	 * @param val
	 *            true => met 1, false => met 0
	 * @return le byte modifié.
	 */
	private static byte setBit(byte b, int i, boolean val) {
		if (val) {
			return (byte) (1 << (7 - i) | b);
		} else {
			return (byte) (-2 << (7 - i) & b);
		}
	}

	/**
	 * b : 0 => bit de poids fort b : 7 => bit de poids faible
	 * 
	 * @param b
	 *            non modifié
	 * @param i
	 * @return la valeur du ième bit de b
	 */
	private static boolean getBit(byte b, int i) {
		byte mask = (byte) (1 << (7 - i));
		return ((mask & b) != 0);
	}

	public byte[] getBytes() {
		byte[] b = new byte[8];
		// pour les 8 byte
		for (int i = 0; i < 8; i++) {
			// pour les 8 bits du byte
			b[i] = 0;
			for (int j = 0; j < 8; j++) {
				if (getValue().get(i * 8 + j)) {
					b[i] = setBit(b[i], j, true);
				}
			}
		}
		return b;
	}

	public static byte[] toBytes(ArrayList<DataBloc> list) {
		byte[] b = new byte[8 * list.size()];
		int i = 0;
		for (DataBloc dataBloc : list) {
			byte[] tmp = dataBloc.getBytes();
			for (int j = 0; j < 8; j++) {
				b[i] = tmp[j];
				i++;
			}
		}
		return b;
	}

	/**
	 * transforme une chaîne de caractère en ArrayList de DataBloc
	 * 
	 * @param text
	 * @return
	 */
	public static ArrayList<DataBloc> toDataBlocs(byte[] tabByte) {
		ArrayList<Byte[]> listByte = new ArrayList<Byte[]>();
		int indexListe = -1;
		int indexTab = 0;
		for (int i = 0; i < tabByte.length; i++) {
			if (indexTab % 8 == 0) {
				listByte.add(new Byte[8]);
				indexListe++;
				indexTab = 0;
			}
			listByte.get(indexListe)[indexTab] = tabByte[i];
			indexTab++;
		}
		// on ajoute des bits de bourage
		if (indexTab < 8) {
			for (int i = indexTab; i < 8; i++) {
				listByte.get(indexListe)[i] = (byte) 0;
			}
		}
		// on remplie l'array list result
		ArrayList<DataBloc> result = new ArrayList<DataBloc>();
		for (int i = 0; i < listByte.size(); i++) {
			result.add(new DataBloc(listByte.get(i)));
		}
		return result;

	}

	public static void main(String[] args) {

		String coucou = "coucou..";
		byte[] bytes = coucou.getBytes();
		for (int i = 0; i < bytes.length; i++) {
			System.out.print(bytes[i] + " ");
		}
		// System.out.println(new String(bytes));
		ArrayList<DataBloc> a = DataBloc.toDataBloc(coucou);
		for (DataBloc d : a) {
			System.out.println("\n" + d.getValue().print());
		}

		byte[] b = toBytes(a);
		for (int i = 0; i < b.length; i++) {
			System.out.print(b[i] + " ");
		}
		String resultCoucou = DataBloc.toString(a);

		for (DataBloc d : toDataBlocs(b)) {
			System.out.println("\n" + d.getValue().print());
		}

		System.out.println(resultCoucou);
		System.out.println((coucou.equals(resultCoucou)));

	}

}
